#include "Thread.h"
#include "ConnectionPool.h"
#include "Format.h"
#include "SqlQuery.h"
#include "publicstruct.h"
#include "OnlineUser.h"
#include "MsgSyncDB.h"
#include "PhoneCode.h"
#include "DDNumCreate.h"
#include "FileMetaData.h"
#include "FileIDGenerator.h"
#include "GroupIDGenerator.h"
#include "FeedSyncTimeLine.h"
#include "DZPLSyncTimeLine.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <iomanip>
#include <filesystem>

Thread::Thread(/* args */)
{
    // 初始化事件集合
    m_base = event_base_new();
    if (!m_base)
    {
        printf("create event_base failed.\n");
        exit(1);
    }

    // 创建管道
    int pipefd[2];
    if (pipe(pipefd) == -1)
    {
        printf("create pipe failed.\n");
        exit(1);
    }
    // 管道事件加入事件集合,解决事件集合一开始为空,监听退出问题
    m_pipeEvent = bufferevent_socket_new(m_base, pipefd[0], BEV_OPT_CLOSE_ON_FREE);
    bufferevent_setcb(m_pipeEvent, pipe_cb, NULL, NULL, NULL);
    bufferevent_enable(m_pipeEvent, EV_READ);
}

Thread::~Thread()
{
    // 释放资源
    event_base_free(m_base);
}

void Thread::start()
{
    // 创建线程
    pthread_create(&m_threadID, NULL, work, this);
    // 线程分离
    pthread_detach(m_threadID);
}

void Thread::addEvent(int fd)
{
    // 创建bufferevent 并将客户端的通信套接字 转化为 事件 ,加入到事件集合中
    struct bufferevent *bev = bufferevent_socket_new(m_base, fd, BEV_OPT_CLOSE_ON_FREE);

    if (NULL == bev)
    {
        printf("bufferevent_socket_new error\n");
        return;
    }
    // 给bufferevent设置回调函数
    bufferevent_setcb(bev, read_cb, write_cb, event_cb, this);
    // 使能回调函数(开启读缓冲)
    bufferevent_enable(bev, EV_READ);
}

void Thread::analysisRequest(const string &request, bufferevent *bev)
{
    // 解析cmd,判断请求类型
    Json::Reader reader;             // json阅读器
    Json::Value root;                // 操作json值
    string cmd;                      // 命令类型
    if (reader.parse(request, root)) // 序列化函数,Json格式的字符串解析成Json::Value
        cmd = root["cmd"].asString();

    // 登录请求
    if (cmd.compare("login") == 0)
        dealLoginRequest(root, bev);
    // 注册请求
    else if (cmd.compare("register") == 0)
        dealRegisterRequest(root, bev);
    // 验证码请求
    else if (cmd.compare("send_code_request") == 0)
        dealSendCodeRequest(root, bev);
    // 获取数据请求
    else if (cmd.compare("get") == 0)
        dealGetDataRequest(root, bev);
    // 添加好友请求
    else if (cmd.compare("add_friend") == 0)
        dealAddFriendRequest(root, bev);
    // 添加好友处理结果
    else if (cmd.compare("add_friend_deal_result") == 0)
        dealAddFriendReply(root, bev);
    // 处理用户离线
    else if (cmd.compare("quit") == 0)
        dealUserQuit(root, bev);
    // 删除好友报文
    else if (cmd.compare("delete_friend") == 0)
        dealDeleteFriend(root, bev);
    // 私聊数据报文
    else if (cmd.compare("private_chat") == 0)
        dealPrivateChat(root, bev);
    // 拉取请求
    else if (cmd.compare("pull_request") == 0)
        dealPullRequest(root, bev);
    // 文件头
    else if (cmd.compare("file_head") == 0)
        dealFileHead(root, bev);
    // 文件上传完毕
    else if (cmd.compare("upload_finish") == 0)
        dealUpLoadFinish(root, bev);
    // 创建群聊
    else if (cmd.compare("create_group") == 0)
        dealCreateGroup(root, bev);
    // 群主解散群聊
    else if (cmd.compare("dissolve_group") == 0)
        dealDissolveGroup(root, bev);
    // 用户退出群聊
    else if (cmd.compare("quit_group") == 0)
        dealQuitGroup(root, bev);
    // 添加群聊请求
    else if (cmd.compare("add_group") == 0)
        dealAddGroup(root, bev);
    // 群聊消息
    else if (cmd.compare("group_chat") == 0)
        dealGroupChat(root, bev);
    // 发表动态
    else if (cmd.compare("announce_feed") == 0)
        dealAnnounceFeed(root, bev);
    // 动态拉取请求
    else if (cmd.compare("feed_pull_request") == 0)
        dealFeedPullRequest(root, bev);
    // 评论动态
    else if (cmd.compare("pl_feed") == 0)
        dealPLFeed(root, bev);
    // 点赞动态
    else if (cmd.compare("like_feed") == 0)
        dealLikeFeed(root, bev);
    // 点赞评论拉取请求
    else if (cmd.compare("dzpl_pull_request") == 0)
        dealDZPLPullRequest(root, bev);
    // 取消点赞
    else if (cmd.compare("unlike_feed") == 0)
        dealUnlikeFeed(root, bev);
    // 准备动态相关数据
    else if (cmd.compare("get_feed") == 0)
        dealGetFeed(root, bev);
    // 准备点赞评论相关数据
    else if (cmd.compare("get_dzpl") == 0)
        dealGetDzpl(root, bev);
    // 消息漫游
    else if (cmd.compare("get_history_msg") == 0)
        dealGetHistoryMsg(root, bev);
    // 群消息漫游
    else if (cmd.compare("get_history_msg_group") == 0)
        dealGetHistoryMsgGroup(root, bev);
    // 群文件上传
    else if (cmd.compare("upload_group_file") == 0)
        dealUploadGroupFile(root, bev);
    // 群文件下载请求
    else if (cmd.compare("download_group_file") == 0)
        dealDownloadGroupFile(root, bev);
    // 准备群文件、群通知、群成员
    else if (cmd.compare("get_groupfile") == 0)
        dealGetGroupFile(root, bev);
    // 编辑个人资料
    else if (cmd.compare("modify_user_info") == 0)
        dealModifyUserInfo(root, bev);
    // 发布群公告
    else if (cmd.compare("release_group_notice") == 0)
        dealReleaseGroupNotice(root, bev);
}

void Thread::dealLoginRequest(Json::Value root, bufferevent *bev)
{
    // 解析DD号和密码
    int user;
    string pwd;
    user = root["user"].asUInt();
    pwd = root["password"].asString(); // asString()序列化json数据为string类型
    printf("DD号和密码 解析结果: user:%d  pwd:%s\n", user, pwd.data());

    const char *login_reply; // 响应报文
    string tmp;
    // 从在线用户链表判断用户是否已经登录
    // if (OnlineUser::getInstance()->judgeUserOnline(user) != nullptr) // 用户已经登录
    // {
    //     Json::Value m_root;                         // 整个Json对象
    //     m_root["cmd"] = Json::Value("login_reply"); // 创建一个key,并赋值为value
    //     m_root["result"] = Json::Value("already_login");
    //     tmp = m_root.toStyledString(); // 格式化转换,多行(每条数据,空格和换行)
    //     login_reply = strdup(tmp.c_str());
    //     cout << "登录请求响应:" << endl
    //          << login_reply;
    //     // 向缓冲区中写数据(向客户端发送数据)
    //     bufferevent_write(bev, login_reply, strlen(login_reply));
    //     return;
    // }

    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();

    // 查询数据库是否存在该记录
    string sql = util::Format("select dd_num,pwd,nick,sex,phone,email,city,gxqm,birthday from user where dd_num = {0} and pwd = '{1}'", user, pwd);
    SqlQuery query(conn);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 获取结果集的行数和列数
    int rows = query.getRows();

    // 封装用户个人信息(json响应报文)
    struct st_userData userInfo;

    // 没有匹配到记录，登录失败
    if (rows == 0)
    {
        Json::Value m_root;                         // 整个Json对象
        m_root["cmd"] = Json::Value("login_reply"); // 创建一个key,并赋值为value
        m_root["result"] = Json::Value("error");
        // Json::FastWriter writer;
        // tmp = writer.write(m_root); // 非格式化转换,只有一行,没有多余的空格和换行
        tmp = m_root.toStyledString(); // 格式化转换,多行(每条数据,空格和换行)
    }
    // 匹配到记录
    else
    {
        userInfo.uid = atoi(query.getRes()[0][0].data());
        userInfo.pwd = query.getRes()[0][1];
        userInfo.nick = query.getRes()[0][2];
        userInfo.sex = query.getRes()[0][3];
        userInfo.phone = query.getRes()[0][4];
        userInfo.email = query.getRes()[0][5];
        userInfo.city = query.getRes()[0][6];
        userInfo.gxqm = query.getRes()[0][7];
        userInfo.birthday = query.getRes()[0][8];
        userInfo.status = 1; // 用户登录, 在线状态

        Json::Value m_root; // 整个json对象
        m_root["cmd"] = Json::Value("login_reply");
        m_root["result"] = Json::Value("success");
        Json::Value userArray; // user数组 存放个人资料
        Json::Value pDataItem; // 个人资料   json对象
        // 编写数组内容  -- 个人资料
        pDataItem["dd_num"] = Json::Value(userInfo.uid);
        pDataItem["pwd"] = Json::Value(userInfo.pwd);
        pDataItem["nick"] = Json::Value(userInfo.nick);
        pDataItem["sex"] = Json::Value(userInfo.sex);
        pDataItem["phone"] = Json::Value(userInfo.phone);
        pDataItem["email"] = Json::Value(userInfo.email);
        pDataItem["city"] = Json::Value(userInfo.city);
        pDataItem["gxqm"] = Json::Value(userInfo.gxqm);
        pDataItem["birthday"] = Json::Value(userInfo.birthday);
        pDataItem["status"] = Json::Value(userInfo.status); // 在线状态
        userArray.append(pDataItem);                        // 将个人资料json对象添加进结果数组
        m_root["user"] = userArray;

        // 编写数组内容  --  好友列表
        Json::Value friendArray; // friends数组(键friends的值) ,存放好友列表
        Json::Value friendsItem; // 好友列表项
        // 获取用户的好友列表
        vector<st_fData> fvec = getFriends(userInfo.uid);
        for (int i = 0; i < fvec.size(); i++)
        {
            friendsItem["dd_num"] = Json::Value(fvec[i].fid);
            friendsItem["nick"] = Json::Value(fvec[i].fnick);
            friendsItem["sex"] = Json::Value(fvec[i].fsex);
            friendsItem["phone"] = Json::Value(fvec[i].phone);
            friendsItem["email"] = Json::Value(fvec[i].email);
            friendsItem["city"] = Json::Value(fvec[i].city);
            friendsItem["gxqm"] = Json::Value(fvec[i].gxqm);
            friendsItem["birthday"] = Json::Value(fvec[i].birthday);
            friendsItem["status"] = Json::Value(fvec[i].status);
            friendArray.append(friendsItem); // 将json对象添加进好友结果数组
        }
        m_root["friends"] = friendArray;

        // 编写数组内容 -- 群组列表
        Json::Value groupArray; // group数组(键group的值) ,存放群组列表
        Json::Value groupItem;  // 群组列表项
        // 获取用户的群组列表
        vector<st_gData> gvec = getGroups(userInfo.uid);
        for (int i = 0; i < gvec.size(); i++)
        {
            groupItem["gid"] = Json::Value(gvec[i].gid);
            groupItem["gname"] = Json::Value(gvec[i].gname);
            groupItem["gboss"] = Json::Value(gvec[i].gboss);
            groupItem["gintroduce"] = Json::Value(gvec[i].gintroduce);

            groupArray.append(groupItem);
        }
        m_root["groups"] = groupArray;

        // 将json转换为string
        tmp = m_root.toStyledString(); // 格式化转换,多行(每条数据,空格和换行)

        // 更新数据库用户状态
        sql = util::Format("update user_status set state = {0} where dd_num = {1}", ONLINE, userInfo.uid);
        if (query.exec(sql) == false)
        {
            printf("%s\n", query.getErrorText().data());
            ConnectionPool::getInstance()->recycleConnObj(conn);
            return;
        }
        // 更新在线用户链表 添加在线用户
        st_onlineUser onlineuser(userInfo.uid, bev);
        OnlineUser::getInstance()->addOnlineUser(onlineuser);

        // 给在线的好友发送好友登录通知
        for (int i = 0; i < fvec.size(); i++)
        {
            if (fvec[i].status == 1)
            { // 好友在线,发送登录通知
                Json::Value m_notice;
                m_notice["cmd"] = Json::Value("friend_login");
                m_notice["friend"] = Json::Value(userInfo.uid);
                string m_tmp = m_notice.toStyledString();
                const char *login_notice = strdup(m_tmp.c_str()); // 好友登录通知
                struct bufferevent *fbev = OnlineUser::getInstance()->judgeUserOnline(fvec[i].fid);
                bufferevent_write(fbev, login_notice, strlen(login_notice)); // 告诉好友,我登录了
            }
        }

    } /*匹配到记录*/

    // 字符串较长时,string -> char* 必须使用这种方法,否则出现乱码,搞死人了
    login_reply = strdup(tmp.c_str());
    cout << "登录请求响应:" << endl
         << login_reply;
    // 向缓冲区中写数据(向客户端发送数据)
    bufferevent_write(bev, login_reply, strlen(login_reply));

    // 处理tcp粘包问题
    // 方法1：设置消息边界：插入特殊分隔符 $
    const char *ch = "$";
    bufferevent_write(bev, ch, strlen(ch));

    // 查询用户是否有离线消息
    sql = util::Format("select sender,recver,msgtype,content,sendtime from msg_sync where recver = {0}", user);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }
    // 获取结果集行数、列数
    rows = query.getRows();

    // 有离线消息
    if (rows > 0)
    {
        printf("离线 rows:%d\n", rows);
        // 将离线消息添加到该用户的同步TimeLine
        for (int i = 0; i < rows; i++)
        {
            struct st_msg msg;
            msg.send = atoi(query.getRes()[i][0].data());
            msg.recv = atoi(query.getRes()[i][1].data());
            msg.type = atoi(query.getRes()[i][2].data());
            msg.contect = query.getRes()[i][3];
            msg.sendtime = query.getRes()[i][4];
            toSyncTimeLine(user, msg);
        }

        // 给用户发送推送通知
        Json::Value y_root;
        y_root["cmd"] = Json::Value("new_push");
        string m_tmp = y_root.toStyledString();
        const char *new_push = strdup(m_tmp.c_str()); // 推送通知
        bufferevent_write(bev, new_push, strlen(new_push));
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    // 用户上线，拉取评论点赞置1
    FeedSyncTimeLine::sync_count[user] = 1;
}

void Thread::dealRegisterRequest(Json::Value root, bufferevent *bev)
{
    // 解析昵称、密码、手机号、验证码
    string nick = root["nick"].asString();
    string pwd = root["pwd"].asString();
    string phone = root["phone"].asString();
    string code = root["code"].asString();

    // 验证手机号是否已被其他用户注册
    if (phoneAlreadyRegister(phone) == true)
    {
        Json::Value m_root;
        m_root["cmd"] = Json::Value("phone_already_register"); // 验证码过期或不正确
        string m_tmp = m_root.toStyledString();
        const char *phone_already_register = strdup(m_tmp.c_str());
        bufferevent_write(bev, phone_already_register, strlen(phone_already_register));
        return;
    }

    // 验证验证码
    if (PhoneCode::getInstance()->codeMatch(phone, code) == false)
    {
        Json::Value m_root;
        m_root["cmd"] = Json::Value("code_out_error"); // 验证码过期或不正确
        string m_tmp = m_root.toStyledString();
        const char *code_error = strdup(m_tmp.c_str());
        bufferevent_write(bev, code_error, strlen(code_error));
        return;
    }

    // 生成DD号
    int dd_num = DDNumCreate::getInstance()->createID();
    string sex;
    if (dd_num % 2 == 1)
    {
        sex = "男";
    }
    else
    {
        sex = "女";
    }

    string email = util::Format("{0}@dd.com", dd_num);
    string city = "湖南郴州";
    string gxqm = "这个人很懒,什么都没有留下...";
    string birthday = "2000-11-20";
    // 存储用户信息到数据库
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("insert into user(seq,dd_num,pwd,nick,sex,phone,email,city,gxqm,birthday) \
    value(null,{0},'{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}')",
                              dd_num, pwd, nick, sex, phone, email, city, gxqm, birthday);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    sql = util::Format("insert into user_status(dd_num,state) value({0},0)", dd_num);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    // 根据性别给用户生成一个默认头像,以DD号命名
    string srcpath;
    string dstpath = util::Format("/DragonIM/img/{0}.png", dd_num);
    if (sex == "男")
        srcpath = "/DragonIM/img/man.png";
    else
        srcpath = "/DragonIM/img/woman.png";
    std::filesystem::copy(srcpath, dstpath);

    // 返回给客户端注册响应
    Json::Value m_root;
    m_root["cmd"] = Json::Value("register_reply");
    m_root["dd_num"] = Json::Value(dd_num);
    string m_tmp = m_root.toStyledString();
    const char *register_reply = strdup(m_tmp.c_str());
    bufferevent_write(bev, register_reply, strlen(register_reply));
}

void Thread::dealSendCodeRequest(Json::Value root, bufferevent *bev)
{
    // 获取手机号
    string phone = root["phone"].asString();

    // 判断手机号是否有效

    // 判断手机号是否已被其他用户注册
    // 手机号已被注册
    if (phoneAlreadyRegister(phone))
    {
        Json::Value z_root;
        z_root["cmd"] = Json::Value("phone_already_register");
        string m_tmp = z_root.toStyledString();
        const char *phone_already_register = strdup(m_tmp.c_str());
        bufferevent_write(bev, phone_already_register, strlen(phone_already_register));
        return;
    }
    // 手机号未被注册
    // 生成一个随机验证码，与手机号关联
    string code = PhoneCode::getInstance()->generatorCode();
    PhoneCode::getInstance()->add(phone, code);

    // 互亿无线三方服务给用户手机发送这个验证码...
}

void Thread::dealGetDataRequest(Json::Value root, bufferevent *bev)
{
    // 解析数据类型 (获取哪方面的数据)
    string type = root["type"].asString();
    // 用户信息
    if (type == "user_info")
    {
        // 解析查询条件,从数据库中查询数据
        Json::Value arr = root["condition"]; // arr数组
        Json::Value obj;
        Json::Reader reader;                        // json阅读器,解释器
        reader.parse(arr[0].toStyledString(), obj); // Json格式的字符串解析成Json::Value  obj通过[]访问对应键的值
        string field = obj["field"].asString();     // 查询的字段,dd_num / nick

        vector<st_fData> find_fvec; // 搜索结果的好友信息列表(模糊查询情况下可能有多个符合条件的)
        if (field == "dd_num")
        {
            int dd_num = obj["text"].asInt();
            string sex = obj["sex"].asString();
            printf("DD号解析结果:%d \n", dd_num);
            find_fvec = getSearchInfo(dd_num, sex); // 获取搜索结果的好友信息列表
        }
        if (field == "nick")
        {
            string nick = obj["text"].asString();
            string sex = obj["sex"].asString();
            printf("昵称解析结果: %s \n", nick.data());
            find_fvec = getSearchInfo(nick, sex); // 获取搜索结果的好友信息列表
        }
        const char *getdata_reply; // 响应报文
        string tmp;
        int rows = find_fvec.size();
        if (rows == 0)
        { // 结果集为空,则用户不存在
            Json::Value m_root;
            m_root["cmd"] = Json::Value("get_user_info_reply");
            m_root["result"] = Json::Value("user_not_exist");
            tmp = m_root.toStyledString();
        }
        else
        {
            Json::Value m_root;
            m_root["cmd"] = Json::Value("get_user_info_reply");
            Json::Value resArray; // 结果数组
            Json::Value resItem;  // 临时 json对象 ,结果数组里的每一个元素
            // 编写数组内容  --  查询结果列表
            // 如果查询结果大于等4个，只取前4个
            int size = find_fvec.size();
            if (size > 3)
            {
                size = 4;
            }
            for (int i = 0; i < size; i++)
            {
                resItem["dd_num"] = Json::Value(find_fvec[i].fid);
                resItem["nick"] = Json::Value(find_fvec[i].fnick);
                resItem["sex"] = Json::Value(find_fvec[i].fsex);
                resArray.append(resItem); // 将json对象添加进好友结果数组
            }
            m_root["result"] = resArray;
            // Json::FastWriter writer;
            // tmp = writer.write(m_root); // 非格式化转换,只有一行,没有多余的空格和换行
            tmp = m_root.toStyledString();
        }
        // 字符串较长时,string -> char* 必须使用这种方法,否则出现乱码,搞死人了
        getdata_reply = strdup(tmp.c_str());
        cout << "好友搜索结果 数据请求响应:" << endl
             << getdata_reply;
        // 向缓冲区中写数据(向客户端发送数据)
        bufferevent_write(bev, getdata_reply, strlen(getdata_reply));
    }
    // 群资料
    else if (type == "group_info")
    {
        // 解析查询条件,从数据库中查询数据
        Json::Value arr = root["condition"]; // arr数组
        Json::Value obj;
        Json::Reader reader;                        // json阅读器,解释器
        reader.parse(arr[0].toStyledString(), obj); // Json格式的字符串解析成Json::Value  obj通过[]访问对应键的值
        string field = obj["field"].asString();     // 查询的字段,gid / gname

        vector<st_gData> find_gvec; // 搜索结果的群资料列表(模糊查询情况下可能有多个符合条件的)
        if (field == "gid")
        {
            int gid = obj["text"].asInt();
            find_gvec = getSearchGroupInfo(gid); // 获取搜索结果的群资料列表
        }
        if (field == "gname")
        {
            string gname = obj["text"].asString();
            find_gvec = getSearchGroupInfo(gname); // 获取搜索结果的群资料列表
        }
        const char *getdata_reply; // 响应报文
        string tmp;
        int rows = find_gvec.size();
        if (rows == 0)
        { // 结果集为空,则群不存在
            Json::Value m_root;
            m_root["cmd"] = Json::Value("get_group_info_reply");
            m_root["result"] = Json::Value("group_not_exist");
            tmp = m_root.toStyledString();
        }
        else
        {
            Json::Value m_root;
            m_root["cmd"] = Json::Value("get_group_info_reply");
            Json::Value resArray; // 结果数组
            Json::Value resItem;  // 临时 json对象 ,结果数组里的每一个元素
            // 编写数组内容  --  查询结果列表
            // 如果查询结果大于等4个，只取前4个
            int size = find_gvec.size();
            if (size > 3)
            {
                size = 4;
            }
            for (int i = 0; i < size; i++)
            {
                resItem["gid"] = Json::Value(find_gvec[i].gid);
                resItem["gname"] = Json::Value(find_gvec[i].gname);
                resItem["gboss"] = Json::Value(find_gvec[i].gboss);
                resItem["gintroduce"] = Json::Value(find_gvec[i].gintroduce);
                resArray.append(resItem); // 将json对象添加进结果数组
            }
            m_root["result"] = resArray;
            // Json::FastWriter writer;
            // tmp = writer.write(m_root); // 非格式化转换,只有一行,没有多余的空格和换行
            tmp = m_root.toStyledString();
        }
        // 字符串较长时,string -> char* 必须使用这种方法,否则出现乱码,搞死人了
        getdata_reply = strdup(tmp.c_str());
        cout << "群聊搜索结果 数据请求响应:" << endl
             << getdata_reply;
        // 向缓冲区中写数据(向客户端发送数据)
        bufferevent_write(bev, getdata_reply, strlen(getdata_reply));
    }
}

void Thread::dealAddFriendRequest(Json::Value root, bufferevent *bev)
{
    // 解析用户和好友的id
    int uid = root["user"].asInt();
    int fuid = root["friend"].asInt();

    // 不能添加自己为好友
    if (uid == fuid)
    {
        Json::Value m_root; // 整个json对象
        m_root["cmd"] = Json::Value("add_friend_reply");
        m_root["result"] = Json::Value("add_myself");
        string tmp = m_root.toStyledString(); // 转为格式化的字符串
        const char *addfriend_reply = strdup(tmp.c_str());
        cout << "添加好友请求响应:" << endl
             << addfriend_reply;
        // 向缓冲区中写数据(向客户端发送数据)
        bufferevent_write(bev, addfriend_reply, strlen(addfriend_reply));
    }
    else
    {
        // 判断两人是否已经是好友
        // 因为好友关系做的限制 <A,B> A一定小于B
        string sql;
        if (uid < fuid)
            sql = util::Format("select seq from friend_relation where uid = {0} and fuid = {1}", uid, fuid);
        else
            sql = util::Format("select seq from friend_relation where uid = {0} and fuid = {1}", fuid, uid);
        // 从数据库连接池获取一个mysql连接
        MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
        SqlQuery query(conn);
        if (query.exec(sql) == false)
        {
            printf("%s\n", query.getErrorText().data());
            ConnectionPool::getInstance()->recycleConnObj(conn);
            return;
        }
        // 获取结果集的行数
        int rows = query.getRows();
        // 两人是好友关系
        if (rows != 0)
        {
            Json::Value m_root; // 整个json对象
            m_root["cmd"] = Json::Value("add_friend_reply");
            m_root["result"] = Json::Value("already_friend");
            string tmp = m_root.toStyledString(); // 转为格式化的字符串
            const char *addfriend_reply = strdup(tmp.c_str());
            cout << "添加好友请求响应:" << endl
                 << addfriend_reply;
            // 向缓冲区中写数据(向客户端发送数据)
            bufferevent_write(bev, addfriend_reply, strlen(addfriend_reply));
        }
        // 两人不是好友关系
        else
        {
            // 给发送方返回 添加好友请求响应
            Json::Value m_root;
            m_root["cmd"] = Json::Value("add_friend_reply");
            m_root["result"] = Json::Value("wait");
            string tmp = m_root.toStyledString(); // 转为格式化的字符串
            const char *addfriend_reply = strdup(tmp.c_str());
            cout << "添加好友请求响应:" << endl
                 << addfriend_reply;
            // 向缓冲区中写数据(向客户端发送数据)
            bufferevent_write(bev, addfriend_reply, strlen(addfriend_reply));

            st_fData udata = getUserInfo(uid);
            struct st_msg msg(uid, fuid, 71, udata.fnick);
            // 将添加好友请求存储到消息同步库
            toMsgSyncDB(msg);

            // 判断好友是否在线
            struct bufferevent *fbev = judgeUserOnline(fuid);
            if (fbev != nullptr)
            {
                cout << "好友" << fuid << "在线" << endl;
                toSyncTimeLine(fuid, msg);
                Json::Value t_root; // 整个json对象
                t_root["cmd"] = Json::Value("new_push");
                string tmp = t_root.toStyledString();
                const char *new_push = strdup(tmp.c_str());
                // 向缓冲区中写数据(向客户端发送数据)
                bufferevent_write(fbev, new_push, strlen(new_push));
            }
        }
        // 回收数据库连接
        ConnectionPool::getInstance()->recycleConnObj(conn);
    }
}

void Thread::dealUserQuit(Json::Value root, bufferevent *bev)
{
    // 获取离线用户id
    int uid = root["user"].asInt();
    // 更新数据库用户状态
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj(); // 获取一条数据库连接
    SqlQuery query(conn);
    string sql = util::Format("update user_status set state = {0} where dd_num = {1}", OFFLINE, uid);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }
    ConnectionPool::getInstance()->recycleConnObj(conn); // 回收数据库连接
    // 更新在线用户链表 删除在线用户
    OnlineUser::getInstance()->deleteOnlineUser(uid);

    // 获取用户的好友列表
    vector<st_fData> fvec = getFriends(uid);
    // 给用户的所有在线好友发送好友离线通知
    for (int i = 0; i < fvec.size(); i++)
    {
        if (fvec[i].status == 1)
        { // 好友在线,发送离线通知
            Json::Value m_notice;
            m_notice["cmd"] = Json::Value("friend_quit");
            m_notice["friend"] = Json::Value(uid);
            string m_tmp = m_notice.toStyledString();
            const char *quit_notice = strdup(m_tmp.c_str()); // 好友离线通知
            struct bufferevent *fbev = OnlineUser::getInstance()->judgeUserOnline(fvec[i].fid);
            bufferevent_write(fbev, quit_notice, strlen(quit_notice)); // 告诉好友,我离线了
        }
    }

    // 用户离线，动态及点赞评论拉取次数置1
    FeedSyncTimeLine::sync_count[uid] = 1;
}

struct bufferevent *Thread::judgeUserOnline(int uid)
{
    return OnlineUser::getInstance()->judgeUserOnline(uid);
}

int Thread::isGroupMember(int uid, int gid)
{
    // 获取一条数据库连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    string sql = util::Format("select gid,memberid from group_relation where memberid = {0} and gid = {1}", uid, gid);
    SqlQuery query(conn);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return -1; // 遇到其他错误
    }
    int row = query.getRows();
    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
    // 数据库没有该用户记录,不是该群成员,返回0
    if (row == 0)
        return 0;
    // 用户是群成员,返回1
    return 1;
}

void Thread::insertGRT(int uid, int gid)
{
    // 获取一条数据库连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    string sql = util::Format("insert into group_relation(seq,gid,memberid) value(null,{0},{1})", gid, uid);
    SqlQuery query(conn);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }
    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
}

void Thread::deleteGRT(int uid, int gid)
{
    // 获取一条数据库连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    string sql = util::Format("delete from group_relation where gid = {0} and memberid = {1}", gid, uid);
    SqlQuery query(conn);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }
    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
}

void Thread::dealAddFriendReply(Json::Value root, bufferevent *bev)
{
    // 解析请求方和接收方 以及 处理结果
    int sender = root["send"].asInt();
    int recver = root["recv"].asInt();
    string result = root["result"].asString();

    // content字段为 处理结果#nick
    st_fData fcv_data = getUserInfo(recver);
    string content = result + "#" + fcv_data.fnick;
    struct st_msg msg(recver, sender, 72, content);
    // 将处理结果存储到消息同步库
    toMsgSyncDB(msg);
    // 若请求方在线，发送推送通知，否则等他下次上线拉取
    struct bufferevent *send_bev = judgeUserOnline(sender);
    if (send_bev != nullptr)
    {
        toSyncTimeLine(sender, msg);
        Json::Value m_root; // 整个json对象
        m_root["cmd"] = Json::Value("new_push");
        string tmp = m_root.toStyledString();
        const char *new_push = strdup(tmp.c_str());
        bufferevent_write(send_bev, new_push, strlen(new_push));
    }

    // 同意才需要向好友关系表添加记录，并给处理方返回请求方的个人信息，方便更新UI
    if (result == "agree")
    {
        // 更新好友关系表,注意插入记录时,uid < fid
        MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
        string sql;
        if (sender < recver)
            sql = util::Format("insert into friend_relation values(null,{0},{1})", sender, recver);
        else
            sql = util::Format("insert into friend_relation values(null,{0},{1})", recver, sender);
        SqlQuery query(conn);
        if (query.exec(sql) == false)
        {
            printf("%s\n", query.getErrorText().data());
            ConnectionPool::getInstance()->recycleConnObj(conn);
            return;
        }
        // 回收数据库连接
        ConnectionPool::getInstance()->recycleConnObj(conn);

        // 给处理方返回请求方的个人信息，方便更新UI
        st_fData fdata = getUserInfo(sender);
        Json::Value z_root; // 整个json对象
        z_root["cmd"] = Json::Value("new_friend");
        z_root["dd_num"] = Json::Value(fdata.fid);
        z_root["nick"] = Json::Value(fdata.fnick);
        z_root["sex"] = Json::Value(fdata.fsex);
        z_root["phone"] = Json::Value(fdata.phone);
        z_root["email"] = Json::Value(fdata.email);
        z_root["city"] = Json::Value(fdata.city);
        z_root["gxqm"] = Json::Value(fdata.gxqm);
        z_root["birthday"] = Json::Value(fdata.birthday);
        z_root["status"] = Json::Value(fdata.status);

        string tmp = z_root.toStyledString();
        const char *new_friend = strdup(tmp.c_str());
        bufferevent_write(bev, new_friend, strlen(new_friend));
    }
}

void Thread::dealDeleteFriend(Json::Value root, bufferevent *bev)
{
    // 获取删除方和接收方
    int user = root["user"].asInt();
    int t_friend = root["friend"].asInt();
    // 获取一条数据库连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    string sql;
    if (user < t_friend)
        sql = util::Format("delete from friend_relation where uid={0} and fuid={1}", user, t_friend);
    else
        sql = util::Format("delete from friend_relation where uid={0} and fuid={1}", t_friend, user);
    SqlQuery query(conn);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 从同步库中删除相关聊天记录
    sql = util::Format("delete from msg_sync where sender = {0} and recver = {1}", user, t_friend);
    query.exec(sql);
    sql = util::Format("delete from msg_sync where sender = {0} and recver = {1}", t_friend, user);
    query.exec(sql);

    // 从存储库中删除相关聊天记录
    sql = util::Format("delete from msg_storage where sender = {0} and recver = {1}", user, t_friend);
    query.exec(sql);
    sql = util::Format("delete from msg_storage where sender = {0} and recver = {1}", t_friend, user);
    query.exec(sql);

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    // 给删除方返回 删除好友响应
    Json::Value m_root; // 整个json对象
    m_root["cmd"] = Json::Value("delete_friend_reply");
    m_root["uid"] = Json::Value(t_friend);
    string tmp = m_root.toStyledString();
    const char *delete_friend_reply = strdup(tmp.c_str());
    bufferevent_write(bev, delete_friend_reply, strlen(delete_friend_reply));

    // 给接收方发送 删除好友通知
    st_fData fdata = getUserInfo(user);
    struct st_msg msg(user, t_friend, 73, fdata.fnick);
    // 存储到同步库
    toMsgSyncDB(msg);

    struct bufferevent *fbev = judgeUserOnline(t_friend);
    if (fbev != nullptr)
    {
        // 存储到同步TimeLine
        toSyncTimeLine(t_friend, msg);
        Json::Value z_root;
        z_root["cmd"] = Json::Value("new_push");
        string tmp = z_root.toStyledString();
        const char *new_push = strdup(tmp.c_str());
        bufferevent_write(fbev, new_push, strlen(new_push));
    }
}

void Thread::dealPrivateChat(Json::Value root, bufferevent *bev)
{
    // 解析发送方、接收方
    int sender = root["send"].asInt();
    int recver = root["recv"].asInt();
    // 解析消息类型、消息内容
    int msg_type = root["type"].asInt();
    string content = root["content"].asString();

    // 如果是私聊文件，content值做处理   将 文件ID ->  /DragonIM/file/0/homework.txt#7751#文件ID
    if (msg_type == 52)
    {
        // 获取文件元信息
        string metaData = FileMetaData::getInstance()->getFMData(content);
        // 拆解文件名和文件大小
        vector<string> vec = split(metaData, '#');
        string path = util::Format("/DragonIM/file/{0}/{1}#{2}#{3}", vec[2], vec[0], vec[1], content);
        content = path;
    }

    // 将消息持久化到消息存储库
    struct st_msg msg(sender, recver, msg_type, content);
    toMsgStorageDB(msg);
    // 将消息推送到消息同步库 以及 双方的同步TimeLine（接收方在线才同步，自己是发送方，一定在线，直接同步）
    toMsgSyncDB(msg);

    // 封装推送通知
    Json::Value m_root;
    m_root["cmd"] = Json::Value("new_push");
    string tmp = m_root.toStyledString();
    const char *new_push = strdup(tmp.c_str());

    toSyncTimeLine(sender, msg);
    bufferevent_write(bev, new_push, strlen(new_push)); // 发送方

    struct bufferevent *fbev = judgeUserOnline(recver);
    // 接收方在线
    if (fbev != nullptr)
    {
        // 接收方在线才加入同步TimeLine，因为用户登录会遍历消息同步库，把离线消息加进同步TimeLine
        toSyncTimeLine(recver, msg);
        // 向缓冲区中写数据(向客户端[请求方]发送数据)
        bufferevent_write(fbev, new_push, strlen(new_push)); // 接收方
    }
}

struct st_fData Thread::getUserInfo(int uid)
{
    // 获取一条数据库连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    string sql = util::Format("select t1.dd_num,t1.nick,t1.sex,t1.phone,t1.email,t1.city,t1.gxqm,t1.birthday,t2.state from `user` t1 join user_status t2 on t1.dd_num=t2.dd_num where t1.dd_num = {0}", uid);
    SqlQuery query(conn);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return st_fData();
    }
    // 获取结果集的行数和列数
    int rows = query.getRows();
    if (rows == 0) // 无结果返回空
        return st_fData();
    st_fData fdata;
    fdata.fid = atoi(query.getRes()[0][0].data());
    fdata.fnick = query.getRes()[0][1];
    fdata.fsex = query.getRes()[0][2];
    fdata.phone = query.getRes()[0][3];
    fdata.email = query.getRes()[0][4];
    fdata.city = query.getRes()[0][5];
    fdata.gxqm = query.getRes()[0][6];
    fdata.birthday = query.getRes()[0][7];
    fdata.status = atoi(query.getRes()[0][8].data());

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
    return fdata;
}

st_gData Thread::getGroupInfo(int gid)
{
    // 获取一条数据库连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    string sql = util::Format("select gid,gname,gboss,gintroduce from `group` where gid = {0}", gid);
    SqlQuery query(conn);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return st_gData();
    }
    // 获取结果集的行数和列数
    int rows = query.getRows();
    if (rows == 0) // 无结果返回空
        return st_gData();
    struct st_gData gdata;
    gdata.gid = atoi(query.getRes()[0][0].data());
    gdata.gname = query.getRes()[0][1];
    gdata.gboss = atoi(query.getRes()[0][2].data());
    gdata.gintroduce = query.getRes()[0][3];
    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
    return gdata;
}

vector<int> Thread::getGroupAllUserID(int gid)
{
    // 获取一条数据库连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    string sql = util::Format("select memberid from group_relation where gid = {0}", gid);
    SqlQuery query(conn);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return vector<int>();
    }
    // 获取结果集的行数和列数
    int rows = query.getRows();
    vector<int> vec;
    for (int i = 0; i < query.getRes().size(); i++)
    {
        int uid = atoi(query.getRes()[i].front().data());
        vec.push_back(uid);
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    return vec;
}

vector<st_fData> Thread::getFriends(int uid)
{
    // 获取一条数据库连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    // 根据用户的uid,获取所有好友的信息
    string sql = util::Format("select u1.dd_num,u1.nick,u1.sex,u2.state,u1.phone,u1.email,u1.city,u1.gxqm,u1.birthday from user u1 join user_status u2 on u1.dd_num = u2.dd_num \
    where u1.dd_num in (select fuid from friend_relation where uid = {0})	union all \
    select u1.dd_num,u1.nick,u1.sex,u2.state,u1.phone,u1.email,u1.city,u1.gxqm,u1.birthday from user u1 join user_status u2 on u1.dd_num = u2.dd_num \
    where u1.dd_num in (select uid from friend_relation where fuid = {0})",
                              uid);
    SqlQuery query(conn);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return vector<st_fData>();
    }
    // 获取结果集的行数和列数
    int rows = query.getRows();

    vector<st_fData> tmp;
    // 将好友信息装入vector容器
    for (int i = 0; i < rows; i++)
    {
        st_fData fdata;
        fdata.fid = atoi(query.getRes()[i][0].data());
        fdata.fnick = query.getRes()[i][1];
        fdata.fsex = query.getRes()[i][2];
        fdata.status = atoi(query.getRes()[i][3].data());
        fdata.phone = query.getRes()[i][4];
        fdata.email = query.getRes()[i][5];
        fdata.city = query.getRes()[i][6];
        fdata.gxqm = query.getRes()[i][7];
        fdata.birthday = query.getRes()[i][8];
        tmp.push_back(fdata);
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    return tmp;
}

vector<int> Thread::getFriendsID(int uid)
{
    // 获取一条数据库连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    // 根据用户的uid,获取所有好友的ID
    string sql = util::Format("select dd_num from user where dd_num in (select fuid from friend_relation where uid = {0})	\
                    union all \
                    select dd_num from user where dd_num in (select uid from friend_relation where fuid = {0})",
                              uid);
    SqlQuery query(conn);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return vector<int>();
    }
    // 获取结果集的行数和列数
    int rows = query.getRows();

    vector<int> tmp;
    // 将好友信息装入vector容器
    for (int i = 0; i < rows; i++)
    {
        int fid;
        fid = atoi(query.getRes()[i][0].data());
        tmp.push_back(fid);
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
    return tmp;
}

vector<st_gData> Thread::getGroups(int uid)
{
    // 获取一条数据库连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    // 根据用户的uid,获取该用户所有群信息
    string sql = util::Format("select g1.gid,g1.gname,g1.gboss,g1.gintroduce from `group` g1 inner join group_relation g2 on g1.gid=g2.gid where g2.memberid = {0}", uid);
    SqlQuery query(conn);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return vector<st_gData>();
    }
    // 获取结果集的行数和列数
    int rows = query.getRows();

    vector<st_gData> tmp;
    // 将群信息装入vector容器
    for (int i = 0; i < rows; i++)
    {
        st_gData gdata;
        gdata.gid = atoi(query.getRes()[i][0].data());
        gdata.gname = query.getRes()[i][1];
        gdata.gboss = atoi(query.getRes()[i][2].data());
        gdata.gintroduce = query.getRes()[i][3];
        tmp.push_back(gdata);
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    return tmp;
}

vector<st_fData> Thread::getSearchInfo(int uid, const string &sex)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql;
    if (sex == "不限")
        sql = util::Format("select dd_num,nick,sex from user where dd_num like '%{0}%'", uid);
    else
        sql = util::Format("select dd_num,nick,sex from user where dd_num like '%{0}%' and sex = '{1}'", uid, sex);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return vector<st_fData>();
    }

    // 获取结果集的行数
    int rows = query.getRows();
    vector<st_fData> tmp;
    // 将好友信息装入vector容器
    for (int i = 0; i < rows; i++)
    {
        st_fData fdata;
        fdata.fid = atoi(query.getRes()[i][0].data());
        fdata.fnick = query.getRes()[i][1];
        fdata.fsex = query.getRes()[i][2];
        tmp.push_back(fdata);
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    return tmp;
}

vector<st_fData> Thread::getSearchInfo(const string &nick, const string &sex)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql;
    if (sex == "不限")
        sql = util::Format("select dd_num,nick,sex from user where nick like '%{0}%'", nick);
    else
        sql = util::Format("select dd_num,nick,sex from user where nick like '%{0}%' and sex = '{1}'", nick, sex);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return vector<st_fData>();
    }
    // 获取结果集的行数
    int rows = query.getRows();
    vector<st_fData> tmp;
    // 将好友信息装入vector容器
    for (int i = 0; i < rows; i++)
    {
        st_fData fdata;
        fdata.fid = atoi(query.getRes()[i][0].data());
        fdata.fnick = query.getRes()[i][1];
        fdata.fsex = query.getRes()[i][2];
        tmp.push_back(fdata);
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    return tmp;
}

vector<st_gData> Thread::getSearchGroupInfo(int gid)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("select gid,gname,gboss,gintroduce from `group` where gid like '%{0}%'", gid);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return vector<st_gData>();
    }

    // 获取结果集的行数
    int rows = query.getRows();
    vector<st_gData> tmp;
    // 将群信息装入vector容器
    for (int i = 0; i < rows; i++)
    {
        st_gData gdata;
        gdata.gid = atoi(query.getRes()[i][0].data());
        gdata.gname = query.getRes()[i][1];
        gdata.gboss = atoi(query.getRes()[i][2].data());
        gdata.gintroduce = query.getRes()[i][3];
        tmp.push_back(gdata);
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    return tmp;
}

vector<st_gData> Thread::getSearchGroupInfo(const string &gname)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("select gid,gname,gboss,gintroduce from `group` where gname like '%{0}%'", gname);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return vector<st_gData>();
    }
    // 获取结果集的行数
    int rows = query.getRows();
    vector<st_gData> tmp;
    // 将群信息装入vector容器
    for (int i = 0; i < rows; i++)
    {
        st_gData gdata;
        gdata.gid = atoi(query.getRes()[i][0].data());
        gdata.gname = query.getRes()[i][1];
        gdata.gboss = atoi(query.getRes()[i][2].data());
        gdata.gintroduce = query.getRes()[i][3];
        tmp.push_back(gdata);
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    return tmp;
}

vector<st_gMemberData> Thread::getGroupMembers(int gid)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("select g1.dd_num,g1.nick from `user` g1 join group_relation g2 on g1.dd_num=g2.memberid where g2.gid={0}", gid);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return vector<st_gMemberData>();
    }
    // 获取结果集的行数
    int rows = query.getRows();
    vector<st_gMemberData> tmp;
    // 将群成员信息装入vector容器
    for (int i = 0; i < rows; i++)
    {
        st_gMemberData gmdata;
        gmdata.mid = atoi(query.getRes()[i][0].data());
        gmdata.nick = query.getRes()[i][1];
        tmp.push_back(gmdata);
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    return tmp;
}

void Thread::toMsgStorageDB(struct st_msg msg)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("insert into msg_storage(seq,sender,recver,msgtype,content,sendtime) values(null,{0},{1},{2},'{3}','{4}')",
                              msg.send, msg.recv, msg.type, msg.contect, msg.sendtime);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
}

void Thread::toMsgSyncDB(st_msg msg)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    // 将时间戳转换为 年月日时分秒  2024-1-28 10:27:58
    // string tim = timestampToString(msg.timestamp);
    string sql = util::Format("insert into msg_sync(seq,sender,recver,msgtype,content,sendtime,recvtime,isrecv) values(null,{0},{1},{2},'{3}','{4}',default,{5})",
                              msg.send, msg.recv, msg.type, msg.contect, msg.sendtime, 0); // datetime 未设置默认值,default插入'0000-00-00'
    cout << "sql:" << sql << endl;
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
}

void Thread::dealPullRequest(Json::Value root, bufferevent *bev)
{
    // 解析TimeLine编号
    int timelineID = root["timelineID"].asInt();
    // 处理tcp粘包问题
    const char *ch = "$";
    cout << "out size: " << MsgSyncDB::getInstance()->getSyncMap()[timelineID].size() << endl;
    // 从同步TimeLine拉取数据返回给客户端
    while (!MsgSyncDB::getInstance()->getSyncMap()[timelineID].empty())
    {
        cout << "size: " << MsgSyncDB::getInstance()->getSyncMap()[timelineID].size() << endl;
        struct st_msg msg = MsgSyncDB::getInstance()->getSyncMap()[timelineID].front(); // 取队头
        MsgSyncDB::getInstance()->getSyncMap()[timelineID].pop_front();                 // 删除队头

        Json::Value m_root; // 整个json对象
        // 私聊文字
        if (msg.type == 51)
        {
            m_root["cmd"] = Json::Value("private_chat");
            m_root["send"] = Json::Value(msg.send);
            m_root["recv"] = Json::Value(msg.recv);
            m_root["type"] = Json::Value(msg.type);
            m_root["content"] = Json::Value(msg.contect);
            m_root["timestamp"] = Json::Value(msg.sendtime);
            string tmp = m_root.toStyledString();
            const char *private_chat = strdup(tmp.c_str());
            cout << "私聊文字:" << tmp;
            bufferevent_write(bev, private_chat, strlen(private_chat));
        }
        // 私聊文件
        else if (msg.type == 52)
        {
            m_root["cmd"] = Json::Value("private_chat");
            m_root["send"] = Json::Value(msg.send);
            m_root["recv"] = Json::Value(msg.recv);
            m_root["type"] = Json::Value(msg.type);
            m_root["content"] = Json::Value(msg.contect);
            m_root["timestamp"] = Json::Value(msg.sendtime);
            string tmp = m_root.toStyledString();
            const char *private_file = strdup(tmp.c_str());
            cout << "私聊文件:" << tmp;
            bufferevent_write(bev, private_file, strlen(private_file));
        }
        // 私聊表情
        else if (msg.type == 53)
        {
            m_root["cmd"] = Json::Value("private_chat");
            m_root["send"] = Json::Value(msg.send);
            m_root["recv"] = Json::Value(msg.recv);
            m_root["type"] = Json::Value(msg.type);
            m_root["content"] = Json::Value(msg.contect);
            m_root["timestamp"] = Json::Value(msg.sendtime);
            string tmp = m_root.toStyledString();
            const char *private_joy = strdup(tmp.c_str());
            cout << "私聊表情:" << tmp;
            bufferevent_write(bev, private_joy, strlen(private_joy));
        }
        // 群聊文字
        else if (msg.type == 54)
        {
            m_root["cmd"] = Json::Value("group_chat");
            m_root["send"] = Json::Value(msg.send);
            m_root["recv"] = Json::Value(msg.recv);
            m_root["type"] = Json::Value(msg.type);
            m_root["content"] = Json::Value(msg.contect);
            m_root["timestamp"] = Json::Value(msg.sendtime);
            string tmp = m_root.toStyledString();
            const char *group_chat = strdup(tmp.c_str());
            cout << "群聊文本:" << tmp;
            bufferevent_write(bev, group_chat, strlen(group_chat));
        }
        // 群聊表情
        else if (msg.type == 55)
        {
            m_root["cmd"] = Json::Value("group_chat");
            m_root["send"] = Json::Value(msg.send);
            m_root["recv"] = Json::Value(msg.recv);
            m_root["type"] = Json::Value(msg.type);
            m_root["content"] = Json::Value(msg.contect);
            m_root["timestamp"] = Json::Value(msg.sendtime);
            string tmp = m_root.toStyledString();
            const char *group_chat = strdup(tmp.c_str());
            cout << "群聊表情:" << tmp;
            bufferevent_write(bev, group_chat, strlen(group_chat));
        }
        // 添加好友请求
        else if (msg.type == 71)
        {
            m_root["cmd"] = Json::Value("addfriend_request");
            m_root["send"] = Json::Value(msg.send);
            m_root["recv"] = Json::Value(msg.recv);
            m_root["type"] = Json::Value(msg.type);
            m_root["content"] = Json::Value(msg.contect);
            m_root["timestamp"] = Json::Value(msg.sendtime);
            string tmp = m_root.toStyledString();
            const char *addfriend_request = strdup(tmp.c_str());
            cout << "添加好友请求:" << tmp;
            bufferevent_write(bev, addfriend_request, strlen(addfriend_request));
        }
        // 添加好友处理结果
        else if (msg.type == 72)
        {
            m_root["cmd"] = Json::Value("add_friend_result");
            m_root["send"] = Json::Value(msg.send);
            m_root["recv"] = Json::Value(msg.recv);
            m_root["type"] = Json::Value(msg.type);
            m_root["content"] = Json::Value(msg.contect);
            m_root["timestamp"] = Json::Value(msg.sendtime);
            string tmp = m_root.toStyledString();
            const char *add_friend_result = strdup(tmp.c_str());
            cout << "添加好友处理结果:" << tmp;
            bufferevent_write(bev, add_friend_result, strlen(add_friend_result));

            // 如果是同意，还需要给请求方返回处理方的个人信息，方便更新UI
            string str = msg.contect.substr(0, 5);
            if (str == "agree")
            {
                bufferevent_write(bev, ch, strlen(ch));
                // 给处理方返回请求方的个人信息，方便更新UI
                st_fData fdata = getUserInfo(msg.send);
                Json::Value z_root; // 整个json对象
                z_root["cmd"] = Json::Value("new_friend");
                z_root["dd_num"] = Json::Value(fdata.fid);
                z_root["nick"] = Json::Value(fdata.fnick);
                z_root["sex"] = Json::Value(fdata.fsex);
                z_root["phone"] = Json::Value(fdata.phone);
                z_root["email"] = Json::Value(fdata.email);
                z_root["city"] = Json::Value(fdata.city);
                z_root["gxqm"] = Json::Value(fdata.gxqm);
                z_root["birthday"] = Json::Value(fdata.birthday);
                z_root["status"] = Json::Value(fdata.status);

                string tmp = z_root.toStyledString();
                const char *new_friend = strdup(tmp.c_str());
                bufferevent_write(bev, new_friend, strlen(new_friend));
            }
        }
        // 删除好友通知
        else if (msg.type == 73)
        {
            m_root["cmd"] = Json::Value("deletefriend_notice");
            m_root["send"] = Json::Value(msg.send);
            m_root["recv"] = Json::Value(msg.recv);
            m_root["type"] = Json::Value(msg.type);
            m_root["content"] = Json::Value(msg.contect);
            m_root["timestamp"] = Json::Value(msg.sendtime);
            string tmp = m_root.toStyledString();
            const char *deletefriend_notice = strdup(tmp.c_str());
            cout << "删除好友通知:" << tmp;
            bufferevent_write(bev, deletefriend_notice, strlen(deletefriend_notice));
        }
        // 解散群聊通知
        else if (msg.type == 74)
        {

            m_root["cmd"] = Json::Value("dissolve_group_notice");
            m_root["send"] = Json::Value(msg.send);
            m_root["recv"] = Json::Value(msg.recv);
            m_root["type"] = Json::Value(msg.type);
            m_root["content"] = Json::Value(msg.contect);
            m_root["timestamp"] = Json::Value(msg.sendtime);
            string tmp = m_root.toStyledString();
            const char *dissolve_group_notice = strdup(tmp.c_str());
            cout << "解散群聊通知:" << tmp;
            bufferevent_write(bev, dissolve_group_notice, strlen(dissolve_group_notice));
        }
        // 创建群聊通知
        else if (msg.type == 75)
        {
            m_root["cmd"] = Json::Value("new_group_notice");
            m_root["send"] = Json::Value(msg.send);
            m_root["recv"] = Json::Value(msg.recv);
            m_root["type"] = Json::Value(msg.type);
            m_root["content"] = Json::Value(msg.contect);
            m_root["timestamp"] = Json::Value(msg.sendtime);
            string tmp = m_root.toStyledString();
            const char *new_group_notice = strdup(tmp.c_str());
            cout << "创建群聊通知:" << tmp;
            bufferevent_write(bev, new_group_notice, strlen(new_group_notice));
        }
        bufferevent_write(bev, ch, strlen(ch));
    }
    // 从同步库中删除数据
    deleteMsgFromSyncDB(timelineID);
}

void Thread::toSyncTimeLine(int uid, struct st_msg msg)
{
    MsgSyncDB::getInstance()->addMsgToSyncTimeLine(uid, msg);
}

void Thread::deleteMsgFromSyncDB(int uid)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("delete from msg_sync where recver = {0}", uid);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
}

void Thread::dealFileHead(Json::Value root, bufferevent *bev)
{

    // //获取输入缓存
    // struct evbuffer * pInput = bufferevent_get_input(bev);
    // //获取输入缓存数据的长度
    // int nLen = evbuffer_get_length(pInput);
    // //获取数据的地址
    // const char * pBody = (const char *)evbuffer_pullup(pInput, nLen);

    // 解析文件名和文件大小
    string fileName = root["filename"].asString();
    long fileSize = root["filesize"].asInt64();

    // 生成文件ID
    string fileID = FileIDGenerator::getInstance()->generatorFileID();
    // 解析文件的分区 ID末3位%7
    int partID = atoi(fileID.substr(fileID.length() - 3).data()) % 7;
    // 将文件ID与文件元数据关联 文件名#文件大小#分区
    string data = fileName + "#" + to_string(fileSize) + "#" + to_string(partID);
    FileMetaData::getInstance()->add(fileID, data);

    // 给客户端返回确认报文,告诉客户端可以发送文件内容了
    Json::Value m_root;
    m_root["cmd"] = Json::Value("file_head_ack");
    m_root["fileID"] = Json::Value(fileID);
    string tmp2 = m_root.toStyledString();
    const char *file_ack = strdup(tmp2.c_str());
    cout << "文件头确认报文:" << tmp2;

    // 返回确认报文
    bufferevent_write(bev, file_ack, strlen(file_ack));
}

void Thread::dealUpLoadFinish(Json::Value root, bufferevent *bev)
{
    // 解析文件ID、文件路径、文件大小
    string fileID = root["fileID"].asString();
    string srvpath = root["srvpath"].asString();
    long filesize = root["filesize"].asInt64();

    // 获取文件信息
    struct stat fileStat;
    long size = 0;
    if (stat(srvpath.data(), &fileStat) == 0)
    {
        size = fileStat.st_size;
        // printf("File size: %lld bytes\n", (long long)fileStat.st_size);      //  文件大小
        // printf("Creation time: %s", ctime(&fileStat.st_ctime));          // 文件创建时间
        // printf("Last access time: %s", ctime(&fileStat.st_atime));       // 最后访问时间
        // printf("Last modification time: %s", ctime(&fileStat.st_mtime));     // 最后修改时间
    }

    Json::Value m_root;
    m_root["cmd"] = Json::Value("upload_reply");
    // 判断文件完整性
    if (size == filesize)
        m_root["result"] = Json::Value("success");
    else
        m_root["result"] = Json::Value("fail");

    string tmp = m_root.toStyledString();
    const char *upload_reply = strdup(tmp.c_str());
    cout << "文件上传响应:" << tmp;

    // 返回文件上传响应
    bufferevent_write(bev, upload_reply, strlen(upload_reply));
}

vector<string> Thread::split(const string &str, char delimiter)
{
    if (str.empty())
        return vector<string>();
    std::vector<std::string> tokens;
    std::string token;
    std::istringstream tokenStream(str);
    while (std::getline(tokenStream, token, delimiter))
    {
        tokens.push_back(token);
    }
    return tokens;
}

bool Thread::phoneAlreadyRegister(const string &phone)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("select seq from user where phone='{0}'", phone);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return true;
    }
    int rows = query.getRows();
    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
    // 无结果，没有被其他用户注册
    if (rows == 0)
        return false;
    return true;
}

void Thread::toFeedStorageDB(struct st_feed feed)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("insert into feed_storage(seq,announcer,pyqtype,content,sendtime,feedID) values(null,{0},{1},'{2}','{3}','{4}')",
                              feed.announcer, feed.type, feed.contect, feed.sendtime, feed.feedID);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
}

void Thread::toFeedSyncTimeLine(int uid, st_feed feed)
{
    FeedSyncTimeLine::getInstance()->addFeedToSyncTimeLine(uid, feed);
}

void Thread::toDZPLDB(st_dzpl dzpl)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("insert into dzpl(seq,uid,feedID,type,content,optime,opID,nick) values(null,{0},'{1}',{2},'{3}','{4}','{5}','{6}')",
                              dzpl.uid, dzpl.feedID, dzpl.type, dzpl.content, dzpl.optime, dzpl.opID, dzpl.nick);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
}

void Thread::removeFromDZPLDB(st_dzpl dzpl)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("delete from dzpl where uid = {0} and feedID = '{1}' and type = {2}", dzpl.uid, dzpl.feedID, 1);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
}

void Thread::toDZPLSyncTimeLine(int uid, st_dzpl dzpl)
{
    DZPLSyncTimeLine::getInstance()->addDZPLToSyncTimeLine(uid, dzpl);
}

void Thread::toFileDB(st_file file)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("insert into file(seq,fid,fname,fsize,fpath,gid,uid,upload_time) \
    value(null,'{0}','{1}',{2},'{3}',{4},{5},'{6}')",
                              file.fid, file.fname, file.fsize, file.fpath, file.gid, file.uid, file.upload_time);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
}

vector<string> Thread::getFeedsID(int uid)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("select feedID from feed_storage t1 join `user` t2 on t1.announcer = t2.dd_num where announcer in (select dd_num from `user` where dd_num in (select fuid from friend_relation where uid = {0}) union all select dd_num from `user` where dd_num in(select uid from friend_relation where fuid = {0}) union all select {0})", uid);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return vector<string>();
    }
    // 获取结果集行数
    int rows = query.getRows();
    vector<string> tmp;

    for (int i = 0; i < rows; i++)
    {
        string feedid = query.getRes()[i].front();
        tmp.push_back(feedid);
    }
    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    return tmp;
}

bool Thread::isGroupExist(int gid)
{
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("select count(*) from `group` where gid = {0}", gid);
    query.exec(sql);
    int count = atoi(query.getRes()[0][0].data());
    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    if (count == 0)
        return false;
    return true;
}

void Thread::dealCreateGroup(Json::Value root, bufferevent *bev)
{
    // 解析群名、群图标、群主、是否通知好友
    string gname = root["gname"].asString();
    int gboss = root["gboss"].asInt();
    string told = root["told"].asString();
    string defaulticon = root["defaulticon"].asString();
    string gicon = root["gicon"].asString();
    string gintroduce = root["gintroduce"].asString();
    // 生成群聊ID
    int gid = GroupIDGenerator::getInstance()->createGroupID();
    // 没有使用默认群图标，则需要将用户自定义的群图标名称改为群ID
    if (defaulticon == "0")
    {
        string oldname = util::Format("/DragonIM/img/{0}", gicon);
        string newname = util::Format("/DragonIM/img/{0}.png", gid);
        cout << "oldname:" << oldname << endl;
        cout << "newname:" << newname << endl;
        if (rename(oldname.data(), newname.data()) != 0)
        {
            printf("groupIcon filename modify failed\n");
            return;
        }
    }
    // 使用默认群图标,那么将默认群图标拷贝一份,并命名为群ID
    else if (defaulticon == "1")
    {
        string srcpath = util::Format("/DragonIM/img/{0}", gicon);
        string dstpath = util::Format("/DragonIM/img/{0}.png", gid);
        // 如果目标图片已经存在,需要先删除目标图片，否则会报错
        if (std::filesystem::exists(dstpath))
        {
            // 先打开再关闭，可以保证删除文件(否则无法删除已经打开的文件)
            FILE *fp = fopen(dstpath.data(), "r");
            fclose(fp);
            int result = unlink(dstpath.data());
            if (result == 0)
            {
                cout << "File deleted successfully." << endl;
            }
            else
            {
                cout << "Failed to delete file." << endl;
            }
        }
        std::filesystem::copy(srcpath, dstpath);
    }

    // 将群ID以及基本信息更新到数据库中
    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("insert into `group`(seq,gid,gname,gboss,gintroduce) value(null,{0},'{1}',{2},'{3}')", gid, gname, gboss, gintroduce);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }
    // 群主也是群成员，加入到群关系表中
    sql = util::Format("insert into group_relation(seq,gid,memberid) value(null,{0},{1})", gid, gboss);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    // 给客户端(创建者)返回创建群聊响应
    Json::Value m_root;
    m_root["cmd"] = Json::Value("create_group_reply");
    m_root["gid"] = Json::Value(gid);
    m_root["gboss"] = Json::Value(gboss);
    m_root["gname"] = Json::Value(gname);
    m_root["gintroduce"] = Json::Value(gintroduce);

    string tmp = m_root.toStyledString();
    const char *create_group_reply = strdup(tmp.c_str());
    cout << "创建群聊响应:" << tmp;

    // 返回文件上传响应
    bufferevent_write(bev, create_group_reply, strlen(create_group_reply));

    // 若需要通知好友，则给所有好友发送群创建通知，告知他们有一个新的群聊被创建
    if (told == "1")
    {
        // 获取用户的好友列表
        vector<int> fvec = getFriendsID(gboss);
        // 将消息存储到消息同步库
        for (int i = 0; i < fvec.size(); i++)
        {
            string content = to_string(gid) + "-" + gname;
            struct st_msg msg(gboss, fvec[i], 75, content);
            toMsgSyncDB(msg);
        }

        Json::Value k_root;
        k_root["cmd"] = Json::Value("new_push");
        tmp = k_root.toStyledString();
        const char *new_push = strdup(tmp.c_str());

        // 若好友在线，发送推送通知
        for (int i = 0; i < fvec.size(); i++)
        {
            struct bufferevent *fbev = judgeUserOnline(fvec[i]);
            if (fbev != nullptr)
            {
                bufferevent_write(fbev, new_push, strlen(new_push));
            }
        }
    }
}

void Thread::dealDissolveGroup(Json::Value root, bufferevent *bev)
{
    // 解析群ID和群主ID
    int gid = root["gid"].asInt();
    int gboss = root["uid"].asInt();

    // 给群主返回 解散群聊响应
    Json::Value m_root;
    m_root["cmd"] = Json::Value("dissolve_group_reply");
    m_root["gid"] = Json::Value(gid);
    string tmp = m_root.toStyledString();
    const char *dissolve_group_reply = strdup(tmp.c_str());
    cout << "解散群聊响应:" << tmp;
    bufferevent_write(bev, dissolve_group_reply, strlen(dissolve_group_reply));
    const char *ch = "$";
    bufferevent_write(bev, ch, strlen(ch));

    // 给群里其他成员返回 解散群聊通知
    // 获取群中所有成员的id
    vector<int> vec_id = getGroupAllUserID(gid);
    st_gData gdata = getGroupInfo(gid);
    // 将通知存储到消息同步库
    for (int i = 0; i < vec_id.size(); i++)
    {
        int recv = vec_id[i];
        // string content = to_string(gid) + "-" + gdata.gname;
        struct st_msg msg(gboss, recv, 74, gdata.gname);
        toMsgSyncDB(msg);
    }

    Json::Value k_root;
    k_root["cmd"] = Json::Value("new_push");
    tmp = k_root.toStyledString();
    const char *new_push = strdup(tmp.c_str());

    // 对于在线的群成员，发送拉取通知
    for (int i = 0; i < vec_id.size(); i++)
    {
        struct bufferevent *fbev = judgeUserOnline(vec_id[i]);
        if (fbev != nullptr)
        {
            bufferevent_write(fbev, new_push, strlen(new_push));
        }
    }

    // 从数据库连接池获取一个mysql连接
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql;
    // 更新group_relation表,群主解散群聊，所有成员都退出群聊
    sql = util::Format("delete from group_relation where gid = {0} ", gid);
    printf("%s\n", sql.data());
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 更新group_notice表，群聊解散，相关群通知都删除
    sql = util::Format("delete from group_notice where gid = {0} ", gid);
    printf("%s\n", sql.data());
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 更新file表，群聊解散，相关群文件都删除
    sql = util::Format("delete from file where gid = {0} ", gid);
    printf("%s\n", sql.data());
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 更新group表,删除表中的记录
    sql = util::Format("delete from `group` where gid = {0}", gid);
    printf("%s\n", sql.data());
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 更新消息同步库,删除表中记录
    string str_ids; // 拼接删除条件
    for (int i = 0; i < vec_id.size(); i++)
    {
        str_ids = to_string(vec_id[i]) + ",";
    }
    // 删除最后一个逗号
    str_ids.pop_back();
    // 删除相关群聊天记录
    sql = util::Format("delete from `msg_sync` where msgtype in (54,55) and content like '{0}%' and recver in ({1})", gid, str_ids);
    printf("%s\n", sql.data());
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }
    // 删除相关群创建通知
    sql = util::Format("delete from `msg_sync` where msgtype=75 and content like '{0}%'", gid);
    printf("%s\n", sql.data());
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 更新消息存储库,删除表中记录
    sql = util::Format("delete from `msg_storage` where msgtype in (54,55) and content like '{0}%' and recver in ({1})", gid, str_ids);
    printf("%s\n", sql.data());
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    ConnectionPool::getInstance()->recycleConnObj(conn);

    // 删除群图标资源
    string giconpath = util::Format("/DragonIM/img/{0}.png", gid);
    // 先打开再关闭，可以保证删除文件(否则无法删除已经打开的文件)
    FILE *fp = fopen(giconpath.data(), "r");
    fclose(fp);
    int result = unlink(giconpath.data());
    if (result == 0)
    {
        cout << "gicon file deleted successfully." << endl;
    }
    else
    {
        cout << "Failed to delete gicon file." << endl;
    }
}

void Thread::dealQuitGroup(Json::Value root, bufferevent *bev)
{
    // 解析uid和gid
    int uid = root["uid"].asInt();
    int gid = root["gid"].asInt();

    // 更新数据库群关系表,删除一条记录
    deleteGRT(uid, gid);

    // 给客户端返回退出群聊响应
    Json::Value m_root;
    m_root["cmd"] = Json::Value("quit_group_reply");
    m_root["gid"] = Json::Value(gid);
    string tmp = m_root.toStyledString();
    const char *quit_group_reply = strdup(tmp.c_str());
    cout << "退出群聊响应:" << tmp;
    // 退出群聊响应
    bufferevent_write(bev, quit_group_reply, strlen(quit_group_reply));

    // 给群里的其他在线用户发送退出群聊通知
    vector<int> vec = getGroupAllUserID(gid);
    Json::Value y_root;
    y_root["cmd"] = Json::Value("quit_group_notice");
    y_root["uid"] = Json::Value(uid);
    y_root["gid"] = Json::Value(gid);
    st_fData fdata = getUserInfo(uid);
    y_root["nick"] = Json::Value(fdata.fnick);
    tmp = y_root.toStyledString();
    const char *quit_group_notice = strdup(tmp.c_str());
    cout << "群成员退出通知:" << tmp;
    // 给群中所有在线成员发送通知
    for (int i = 0; i < vec.size(); i++)
    {
        struct bufferevent *fbev = judgeUserOnline(vec[i]);
        if (fbev != nullptr)
        {
            bufferevent_write(fbev, quit_group_notice, strlen(quit_group_notice));
        }
    }
}

void Thread::dealAddGroup(Json::Value root, bufferevent *bev)
{
    // 解析uid和gid
    int uid = root["uid"].asInt();
    int gid = root["gid"].asInt();

    // 判断群聊是否存在
    if (isGroupExist(gid) == false)
    {
        Json::Value m_root;
        m_root["cmd"] = Json::Value("add_group_reply");
        m_root["result"] = Json::Value("group_not_exist");
        string tmp = m_root.toStyledString();
        const char *add_group_reply = strdup(tmp.c_str());
        cout << "加入群聊响应:" << tmp;

        // 返回加入群聊响应
        bufferevent_write(bev, add_group_reply, strlen(add_group_reply));
    }

    // 判断用户是否是群成员
    int ret = isGroupMember(uid, gid);
    printf("ret=%d\n", ret);
    // 用户已经是群成员
    if (ret == 1)
    {
        Json::Value m_root;
        m_root["cmd"] = Json::Value("add_group_reply");
        m_root["result"] = Json::Value("already_gmember");
        string tmp = m_root.toStyledString();
        const char *add_group_reply = strdup(tmp.c_str());
        cout << "加入群聊响应:" << tmp;

        // 返回加入群聊响应
        bufferevent_write(bev, add_group_reply, strlen(add_group_reply));
    }
    // 用户不是群成员
    else if (ret == 0)
    {

        // 获取该群的所有用户的(先获取，不然加入数据库后再获取会让该成员添加两次)
        vector<int> vec = getGroupAllUserID(gid);

        // 更新数据库群关系表,插入一条记录
        insertGRT(uid, gid);
        // 给用户返回加入群聊响应
        Json::Value z_root;
        struct st_gData gdata = getGroupInfo(gid);
        z_root["cmd"] = Json::Value("add_group_reply");
        z_root["gid"] = Json::Value(gdata.gid);
        z_root["gname"] = Json::Value(gdata.gname);
        z_root["gboss"] = Json::Value(gdata.gboss);
        z_root["gintroduce"] = Json::Value(gdata.gintroduce);
        z_root["result"] = Json::Value("success");
        string tmp = z_root.toStyledString();
        const char *add_group_reply = strdup(tmp.c_str());
        cout << "加入群聊响应:" << tmp;

        const char *ch = "$";

        // 返回加入群聊响应
        bufferevent_write(bev, add_group_reply, strlen(add_group_reply));
        bufferevent_write(bev, ch, strlen(ch));

        // 给群中的所有在线用户返回新成员加入通知，告知有新成员加入
        st_fData udata = getUserInfo(uid);
        Json::Value y_root;
        y_root["cmd"] = Json::Value("new_groupMember");
        y_root["uid"] = Json::Value(uid);
        y_root["nick"] = Json::Value(udata.fnick);
        y_root["gid"] = Json::Value(gid);
        tmp = y_root.toStyledString();
        const char *new_groupMember = strdup(tmp.c_str());
        cout << "新成员加入通知:" << tmp;
        // 给群中所有在线成员发送通知
        for (int i = 0; i < vec.size(); i++)
        {
            struct bufferevent *fbev = judgeUserOnline(vec[i]);
            if (fbev != nullptr)
            {
                bufferevent_write(fbev, new_groupMember, strlen(new_groupMember));
            }
        }
    }
    // 其他错误
    else
        return;
}

void Thread::dealGroupChat(Json::Value root, bufferevent *bev)
{
    // 解析发送方、接收方（群ID）、消息类型、消息内容
    int send = root["send"].asInt();
    int recv = root["recv"].asInt();
    int msg_type = root["type"].asInt();
    string content = root["content"].asString();

    // 封装推送通知
    Json::Value m_root;
    m_root["cmd"] = Json::Value("new_push");
    string tmp = m_root.toStyledString();
    const char *new_push = strdup(tmp.c_str());

    // 获取群聊的所有成员
    vector<int> vec_allid = getGroupAllUserID(recv);
    for (int i = 0; i < vec_allid.size(); i++)
    {
        int mid = vec_allid[i];
        // 接收方为群成员，内容为 群ID-数据内容
        string t_content = util::Format("{0}-{1}", recv, content);
        struct st_msg msg(send, mid, msg_type, t_content);
        // 将消息持久化到消息存储库
        toMsgStorageDB(msg);
        // 将消息推送到消息同步库
        toMsgSyncDB(msg);
        // 若接收方在线，将消息推送到接收方的同步TimeLine，并发送推送通知
        struct bufferevent *fbev = OnlineUser::getInstance()->judgeUserOnline(mid);
        // 接收方在线
        if (fbev != nullptr)
        {
            toSyncTimeLine(mid, msg);
            bufferevent_write(fbev, new_push, strlen(new_push));
        }
    }
}

void Thread::dealAnnounceFeed(Json::Value root, bufferevent *bev)
{
    // 解析发布者、动态类型、动态内容
    int announcer = root["announcer"].asInt();
    string nick = root["nick"].asString();
    int pyqtype = root["pyqtype"].asInt();
    string content = root["content"].asString();

    // 封装动态消息
    struct st_feed feed(announcer, nick, pyqtype, content);
    // 将动态消息持久化到发布表（动态存储库）
    toFeedStorageDB(feed);
    // 将动态添加到所有相关者的Feed同步TimeLine (自己一定在线，直接同步)
    toFeedSyncTimeLine(announcer, feed);

    // 封装新feed通知
    Json::Value m_root; // 整个json对象
    m_root["cmd"] = Json::Value("new_feed");
    string tmp = m_root.toStyledString();
    const char *new_feed = strdup(tmp.c_str());
    // 发布者一定在线，直接同步
    bufferevent_write(bev, new_feed, strlen(new_feed));

    // 获取发布者的好友列表
    vector<struct st_fData> fvec = getFriends(announcer);
    for (int i = 0; i < fvec.size(); i++)
    {
        struct bufferevent *fbev = OnlineUser::getInstance()->judgeUserOnline(fvec[i].fid);
        // 接收方在线
        if (fbev != nullptr)
        {
            toFeedSyncTimeLine(fvec[i].fid, feed);
            bufferevent_write(fbev, new_feed, strlen(new_feed)); // 接收方
        }
    }
}

void Thread::dealFeedPullRequest(Json::Value root, bufferevent *bev)
{
    // 解析TimeLine编号
    int timelineID = root["timelineID"].asInt();
    // 处理tcp粘包问题
    const char *ch = "$";
    // 从feed同步TimeLine拉取数据返回给客户端
    while (!FeedSyncTimeLine::getInstance()->getSyncMap()[timelineID].empty())
    {
        cout << "size: " << FeedSyncTimeLine::getInstance()->getSyncMap()[timelineID].size() << endl;
        struct st_feed feed = FeedSyncTimeLine::getInstance()->getSyncMap()[timelineID].front(); // 取队头
        FeedSyncTimeLine::getInstance()->getSyncMap()[timelineID].pop_front();                   // 删除队头

        Json::Value m_root; // 整个json对象
        // 文字动态
        if (feed.type == 95)
        {
            m_root["cmd"] = Json::Value("feed");
            m_root["announcer"] = Json::Value(feed.announcer);
            m_root["nick"] = Json::Value(feed.nick);
            m_root["pyqtype"] = Json::Value(feed.type);
            m_root["content"] = Json::Value(feed.contect);
            m_root["sendtime"] = Json::Value(feed.sendtime);
            m_root["feedID"] = Json::Value(feed.feedID);
            string tmp = m_root.toStyledString();
            const char *feed = strdup(tmp.c_str());
            cout << "文字动态:" << tmp;
            bufferevent_write(bev, feed, strlen(feed));
        }
        // 图文动态
        else if (feed.type == 96)
        {
            m_root["cmd"] = Json::Value("feed");
            m_root["announcer"] = Json::Value(feed.announcer);
            m_root["nick"] = Json::Value(feed.nick);
            m_root["pyqtype"] = Json::Value(feed.type);
            m_root["content"] = Json::Value(feed.contect);
            m_root["sendtime"] = Json::Value(feed.sendtime);
            m_root["feedID"] = Json::Value(feed.feedID);
            string tmp = m_root.toStyledString();
            const char *feed = strdup(tmp.c_str());
            cout << "图文动态:" << tmp;
            bufferevent_write(bev, feed, strlen(feed));
        }
        bufferevent_write(bev, ch, strlen(ch));
    }

    // 只执行 1 次
    if (FeedSyncTimeLine::sync_count[timelineID] == 1)
    {
        Json::Value z_root;
        z_root["cmd"] = Json::Value("new_dzpl");
        string tmp = z_root.toStyledString();
        const char *new_dzpl = strdup(tmp.c_str());
        cout << "同时拉取点赞评论:" << tmp;
        bufferevent_write(bev, new_dzpl, strlen(new_dzpl));
        bufferevent_write(bev, ch, strlen(ch));

        // 拉取评论点赞置2
        FeedSyncTimeLine::sync_count[timelineID] == 2;
    }
}

void Thread::dealPLFeed(Json::Value root, bufferevent *bev)
{
    // 解析UID、nick、feedID、content、announcer
    int uid = root["uid"].asInt();
    string nick = root["nick"].asString();
    string feedID = root["feedID"].asString();
    string content = root["content"].asString();
    int announcer = root["announcer"].asInt();
    // 持久化到点赞评论表中
    struct st_dzpl dzpl(uid, nick, feedID, 2, content);
    toDZPLDB(dzpl);

    // 封装新dzpl通知
    Json::Value m_root; // 整个json对象
    m_root["cmd"] = Json::Value("new_dzpl");
    string tmp = m_root.toStyledString();
    const char *new_dzpl = strdup(tmp.c_str());

    // 获取发布者的好友列表ID
    vector<int> fidvec = getFriendsID(announcer);
    fidvec.push_back(announcer); // 把发布者自己添加进去

    for (int i = 0; i < fidvec.size(); i++)
    {
        struct bufferevent *fbev = OnlineUser::getInstance()->judgeUserOnline(fidvec[i]);
        // 接收方在线
        if (fbev != nullptr)
        {
            toDZPLSyncTimeLine(fidvec[i], dzpl);
            bufferevent_write(fbev, new_dzpl, strlen(new_dzpl)); // 接收方
        }
    }
}

void Thread::dealLikeFeed(Json::Value root, bufferevent *bev)
{
    // 解析UID、nick、feedID、content、announcer
    int uid = root["uid"].asInt();
    string nick = root["nick"].asString();
    string feedID = root["feedID"].asString();
    string content = root["content"].asString();
    int announcer = root["announcer"].asInt();
    // 持久化到点赞评论表中
    struct st_dzpl dzpl(uid, nick, feedID, 1, content);
    toDZPLDB(dzpl);

    // 封装新dzpl通知
    Json::Value m_root; // 整个json对象
    m_root["cmd"] = Json::Value("new_dzpl");
    string tmp = m_root.toStyledString();
    const char *new_dzpl = strdup(tmp.c_str());

    // 获取发布者的好友ID
    vector<int> fidvec = getFriendsID(announcer);
    fidvec.push_back(announcer);
    for (int i = 0; i < fidvec.size(); i++)
    {
        struct bufferevent *fbev = OnlineUser::getInstance()->judgeUserOnline(fidvec[i]);
        // 接收方在线
        if (fbev != nullptr)
        {
            toDZPLSyncTimeLine(fidvec[i], dzpl);
            bufferevent_write(fbev, new_dzpl, strlen(new_dzpl)); // 接收方
        }
    }
}

void Thread::dealDZPLPullRequest(Json::Value root, bufferevent *bev)
{
    // 解析TimeLine编号
    int timelineID = root["timelineID"].asInt();
    // 处理tcp粘包问题
    const char *ch = "$";
    // 从feed同步TimeLine拉取数据返回给客户端
    while (!DZPLSyncTimeLine::getInstance()->getSyncMap()[timelineID].empty())
    {
        cout << "size: " << DZPLSyncTimeLine::getInstance()->getSyncMap()[timelineID].size() << endl;
        struct st_dzpl dzpl = DZPLSyncTimeLine::getInstance()->getSyncMap()[timelineID].front(); // 取队头
        DZPLSyncTimeLine::getInstance()->getSyncMap()[timelineID].pop_front();                   // 删除队头

        Json::Value m_root; // 整个json对象
        // 评论
        if (dzpl.type == 2)
        {
            m_root["cmd"] = Json::Value("pl");
            m_root["uid"] = Json::Value(dzpl.uid);
            m_root["nick"] = Json::Value(dzpl.nick);
            m_root["feedID"] = Json::Value(dzpl.feedID);
            m_root["type"] = Json::Value(dzpl.type);
            m_root["content"] = Json::Value(dzpl.content);
            m_root["optime"] = Json::Value(dzpl.optime);
            m_root["opID"] = Json::Value(dzpl.opID);
            string tmp = m_root.toStyledString();
            const char *pl = strdup(tmp.c_str());
            cout << "评论:" << tmp;
            bufferevent_write(bev, pl, strlen(pl));
        }
        // 点赞
        else if (dzpl.type == 1)
        {
            m_root["cmd"] = Json::Value("dz");
            m_root["uid"] = Json::Value(dzpl.uid);
            m_root["nick"] = Json::Value(dzpl.nick);
            m_root["feedID"] = Json::Value(dzpl.feedID);
            m_root["type"] = Json::Value(dzpl.type);
            m_root["content"] = Json::Value(dzpl.content);
            m_root["optime"] = Json::Value(dzpl.optime);
            m_root["opID"] = Json::Value(dzpl.opID);
            string tmp = m_root.toStyledString();
            const char *dz = strdup(tmp.c_str());
            cout << "点赞:" << tmp;
            bufferevent_write(bev, dz, strlen(dz));
        }
        // 取消点赞
        else if (dzpl.type == 3)
        {
            m_root["cmd"] = Json::Value("undz");
            m_root["uid"] = Json::Value(dzpl.uid);
            m_root["nick"] = Json::Value(dzpl.nick);
            m_root["feedID"] = Json::Value(dzpl.feedID);
            m_root["type"] = Json::Value(dzpl.type);
            m_root["content"] = Json::Value(dzpl.content);
            m_root["optime"] = Json::Value(dzpl.optime);
            m_root["opID"] = Json::Value(dzpl.opID);
            string tmp = m_root.toStyledString();
            const char *undz = strdup(tmp.c_str());
            cout << "取消点赞:" << tmp;
            bufferevent_write(bev, undz, strlen(undz));
        }
        bufferevent_write(bev, ch, strlen(ch));
    }
}

void Thread::dealUnlikeFeed(Json::Value root, bufferevent *bev)
{
    // 解析UID、nick、feedID、content、announcer
    int uid = root["uid"].asInt();
    string nick = root["nick"].asString();
    string feedID = root["feedID"].asString();
    string content = root["content"].asString();
    int announcer = root["announcer"].asInt();
    struct st_dzpl dzpl(uid, nick, feedID, 3, content);
    // 从点赞评论表删除对应记录
    removeFromDZPLDB(dzpl);

    // 封装新dzpl通知
    Json::Value m_root; // 整个json对象
    m_root["cmd"] = Json::Value("new_dzpl");
    string tmp = m_root.toStyledString();
    const char *new_dzpl = strdup(tmp.c_str());

    // 获取发布者的好友ID
    vector<int> fidvec = getFriendsID(announcer);
    fidvec.push_back(announcer);
    for (int i = 0; i < fidvec.size(); i++)
    {
        struct bufferevent *fbev = OnlineUser::getInstance()->judgeUserOnline(fidvec[i]);
        // 接收方在线
        if (fbev != nullptr)
        {
            toDZPLSyncTimeLine(fidvec[i], dzpl);
            bufferevent_write(fbev, new_dzpl, strlen(new_dzpl)); // 接收方
        }
    }
}

void Thread::dealGetHistoryMsg(Json::Value root, bufferevent *bev)
{
    // 解析uid、fid
    int uid = root["uid"].asInt();
    int fid = root["fid"].asInt();

    // 从消息存储库拉取所有与两人有关的私聊消息
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("select sender,recver,msgtype,content,sendtime from msg_storage where sender={0} and recver = {1} and msgtype in(51,52,53) union all select sender,recver,msgtype,content,sendtime from msg_storage where sender={1} and recver = {0} and msgtype in(51,52,53)", uid, fid);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }
    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    // 讲这些消息存储到请求方的同步TimeLIne
    int rows = query.getRows();

    for (int i = 0; i < rows; i++)
    {
        struct st_msg msg;
        msg.send = atoi(query.getRes()[i][0].data());
        msg.recv = atoi(query.getRes()[i][1].data());
        msg.type = atoi(query.getRes()[i][2].data());
        msg.contect = query.getRes()[i][3];
        msg.sendtime = query.getRes()[i][4];
        toSyncTimeLine(uid, msg);
    }

    // 给请求方发送推送通知
    Json::Value m_root; // 整个json对象
    m_root["cmd"] = Json::Value("new_push");
    string tmp = m_root.toStyledString();
    const char *new_push = strdup(tmp.c_str());

    bufferevent_write(bev, new_push, strlen(new_push));
}

void Thread::dealGetHistoryMsgGroup(Json::Value root, bufferevent *bev)
{
    // 解析uid、gid
    int uid = root["uid"].asInt();
    int gid = root["gid"].asInt();

    // 从消息存储库拉取所有与群有关的群聊消息
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    string sql = util::Format("select sender,recver,msgtype,content,sendtime from msg_storage where recver = {0} and msgtype in(54,55) and content like '{1}%'", uid, gid);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }
    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    // 讲这些消息存储到请求方的同步TimeLIne
    int rows = query.getRows();

    for (int i = 0; i < rows; i++)
    {
        struct st_msg msg;
        msg.send = atoi(query.getRes()[i][0].data());
        msg.recv = atoi(query.getRes()[i][1].data());
        msg.type = atoi(query.getRes()[i][2].data());
        msg.contect = query.getRes()[i][3];
        msg.sendtime = query.getRes()[i][4];
        toSyncTimeLine(uid, msg);
    }

    // 给请求方发送推送通知
    Json::Value m_root; // 整个json对象
    m_root["cmd"] = Json::Value("new_push");
    string tmp = m_root.toStyledString();
    const char *new_push = strdup(tmp.c_str());

    bufferevent_write(bev, new_push, strlen(new_push));
}

void Thread::dealUploadGroupFile(Json::Value root, bufferevent *bev)
{
    // 解析fid、gid、uid
    string fid = root["fid"].asString();
    int gid = root["gid"].asInt();
    int uid = root["uid"].asInt();
    string nick = root["nick"].asString();
    // 根据fid获取fname、fsize、fpath
    string metadata = FileMetaData::getInstance()->getFMData(fid);
    vector<string> vec_meta = split(metadata, '#');
    string fname = vec_meta[0];
    long fsize = atoi(vec_meta[1].data());
    string fpath = util::Format("/DragonIM/file/{0}/{1}", vec_meta[2], fname);

    struct st_file file(fid, fname, fsize, fpath, gid, uid);
    // 持久化到文件库
    toFileDB(file);

    Json::Value m_root;
    m_root["cmd"] = Json::Value("new_group_file");
    m_root["fid"] = Json::Value(file.fid);
    m_root["fname"] = Json::Value(file.fname);
    m_root["fsize"] = Json::Value(file.fsize);
    m_root["fpath"] = Json::Value(file.fpath);
    m_root["gid"] = Json::Value(file.gid);
    m_root["uid"] = Json::Value(file.uid);
    m_root["upload_time"] = Json::Value(file.upload_time);
    m_root["nick"] = Json::Value(nick);
    string tmp = m_root.toStyledString();
    const char *new_group_file = strdup(tmp.c_str());
    cout << "新群文件:" << endl
         << tmp;

    // 给该群在线的群成员发送新群文件
    vector<int> vec_id = getGroupAllUserID(gid);
    for (int i = 0; i < vec_id.size(); i++)
    {
        struct bufferevent *fbev = judgeUserOnline(vec_id[i]);
        if (fbev != nullptr)
        {
            bufferevent_write(fbev, new_group_file, strlen(new_group_file));
        }
    }
}

void Thread::dealGetDzpl(Json::Value root, bufferevent *bev)
{
    // 解析 timeLineID
    int uid = root["timelineID"].asInt();

    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    // 查询用户以及用户所有好友发布的动态中所有相关点赞评论
    // 先获取这些动态ID，根据动态ID查找相关点赞评论
    vector<string> all_vec = getFeedsID(uid);
    string str_ids;
    for (int k = 0; k < all_vec.size(); k++)
    {
        str_ids = str_ids + "'" + all_vec[k] + "'" + ",";
    }
    // 删除最后一个逗号
    str_ids.pop_back();

    string sql = util::Format("select uid,feedID,type,content,optime,opID,nick from dzpl where feedID in({0})", str_ids);
    printf("sql: %s\n", sql.data());

    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }
    // 获取结果集行数、列数
    int rows = query.getRows();

    if (rows > 0)
    {
        printf("评论 rows:%d\n", rows);
        // 将评论添加到该用户的DZPL同步TimeLine
        for (int j = 0; j < rows; j++)
        {
            struct st_dzpl dzpl;
            dzpl.uid = atoi(query.getRes()[j][0].data());
            dzpl.feedID = query.getRes()[j][1];
            dzpl.type = atoi(query.getRes()[j][2].data());
            dzpl.content = query.getRes()[j][3];
            dzpl.optime = query.getRes()[j][4];
            dzpl.opID = query.getRes()[j][5];
            dzpl.nick = query.getRes()[j][6];
            toDZPLSyncTimeLine(uid, dzpl);
        }

        // 给用户发送新点赞评论通知
        Json::Value y_root;
        y_root["cmd"] = Json::Value("new_dzpl");
        string m_tmp = y_root.toStyledString();
        const char *new_dzpl = strdup(m_tmp.c_str()); // 新点赞评论
        bufferevent_write(bev, new_dzpl, strlen(new_dzpl));
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
}

void Thread::dealDownloadGroupFile(Json::Value root, bufferevent *bev)
{
    // 解析文件ID
    string fileID = root["fileID"].asString();

    // 获取文件的元数据
    string metadata = FileMetaData::getInstance()->getFMData(fileID);

    // 解析文件资源路径
    vector<string> vec = split(metadata, '#');
    string srvpath = util::Format("/DragonIM/file/{0}/{1}", vec[2], vec[0]);

    // 给客户端返回文件资源路径
    Json::Value m_root;
    m_root["cmd"] = Json::Value("file_srvpath");
    m_root["srvpath"] = Json::Value(srvpath);
    string tmp = m_root.toStyledString();
    const char *file_srvpath = strdup(tmp.c_str());
    bufferevent_write(bev, file_srvpath, strlen(file_srvpath));
}

void Thread::dealGetGroupFile(Json::Value root, bufferevent *bev)
{
    // 解析 timeLineID
    int gid = root["gid"].asInt();

    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    // 查询群文件
    string sql = util::Format("select t1.fid,t1.fname,t1.fsize,t1.fpath,t1.gid,t1.uid,t1.upload_time,t2.nick from file t1 join `user` t2 on t1.uid=t2.dd_num where gid = {0}", gid);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }
    // 获取结果集行数
    int rows = query.getRows();

    const char *ch = "$";
    // 该群有群文件
    if (rows > 0)
    {
        printf("群文件 rows:%d\n", rows);
        // 将群文件信息返回
        for (int i = 0; i < rows; i++)
        {
            Json::Value m_root;
            m_root["cmd"] = Json::Value("new_group_file");
            m_root["fid"] = Json::Value(query.getRes()[i][0]);
            m_root["fname"] = Json::Value(query.getRes()[i][1]);
            m_root["fsize"] = Json::Value(atoi(query.getRes()[i][2].data()));
            m_root["fpath"] = Json::Value(query.getRes()[i][3]);
            m_root["gid"] = Json::Value(atoi(query.getRes()[i][4].data()));
            m_root["uid"] = Json::Value(atoi(query.getRes()[i][5].data()));
            m_root["upload_time"] = Json::Value(query.getRes()[i][6]);
            m_root["nick"] = Json::Value(query.getRes()[i][7]);
            string tmp = m_root.toStyledString();
            const char *new_group_file = strdup(tmp.c_str());
            cout << "新群文件:" << endl
                 << tmp;
            bufferevent_write(bev, new_group_file, strlen(new_group_file));
            bufferevent_write(bev, ch, strlen(ch));
        }
    }

    // 查询群公告
    sql = util::Format("select uid,gid,content,sendtime from group_notice where gid = {0}", gid);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    // 获取结果集行数
    rows = query.getRows();

    // 该群有群公告
    if (rows > 0)
    {
        printf("群公告 rows:%d\n", rows);
        // 将群公告信息返回
        for (int i = 0; i < rows; i++)
        {
            Json::Value m_root;
            m_root["cmd"] = Json::Value("new_groupnotice");
            m_root["uid"] = Json::Value(atoi(query.getRes()[i][0].data()));
            m_root["gid"] = Json::Value(atoi(query.getRes()[i][1].data()));
            m_root["content"] = Json::Value(query.getRes()[i][2]);
            m_root["sendtime"] = Json::Value(query.getRes()[i][3]);
            string tmp = m_root.toStyledString();
            const char *new_groupnotice = strdup(tmp.c_str());
            cout << "新群公告:" << endl
                 << tmp;
            bufferevent_write(bev, new_groupnotice, strlen(new_groupnotice));
            bufferevent_write(bev, ch, strlen(ch));
        }
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    // 查询群成员
    vector<st_gMemberData> gmvec = getGroupMembers(gid); // 获取群的群成员列表

    rows = gmvec.size();

    printf("群成员 rows:%d\n", rows);
    // 将群成员信息返回
    for (int i = 0; i < rows; i++)
    {
        Json::Value m_root;
        m_root["cmd"] = Json::Value("new_groupMember");
        m_root["uid"] = Json::Value(gmvec[i].mid);
        m_root["nick"] = Json::Value(gmvec[i].nick);
        m_root["gid"] = Json::Value(gid);
        string tmp = m_root.toStyledString();
        const char *new_groupMember = strdup(tmp.c_str());
        cout << "群成员:" << endl
             << tmp;
        bufferevent_write(bev, new_groupMember, strlen(new_groupMember));
        bufferevent_write(bev, ch, strlen(ch));
    }
}

void Thread::dealModifyUserInfo(Json::Value root, bufferevent *bev)
{
    // 解析用户信息
    int dd_num = root["dd_num"].asInt();
    string nick = root["nick"].asString();
    string sex = root["sex"].asString();
    string phone = root["phone"].asString();
    string email = root["email"].asString();
    string city = root["city"].asString();
    string gxqm = root["gxqm"].asString();
    string birthday = root["birthday"].asString();

    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    // 更新用户数据
    string sql = util::Format("update `user` set nick='{1}',sex='{2}',phone='{3}',email='{4}',city='{5}',gxqm='{6}',birthday='{7}' where dd_num = {0}", dd_num, nick, sex, phone, email, city, gxqm, birthday);
    printf("sql:%s\n", sql.data());
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }

    Json::Value m_root;
    m_root["cmd"] = Json::Value("modify_user_info_reply");
    m_root["result"] = Json::Value("success");
    string tmp = m_root.toStyledString();
    cout << "编辑个人资料响应:" << endl
         << tmp;
    const char *modify_user_info_reply = strdup(tmp.c_str());
    bufferevent_write(bev, modify_user_info_reply, strlen(modify_user_info_reply));

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
}

void Thread::dealReleaseGroupNotice(Json::Value root, bufferevent *bev)
{
    // 解析uid,gid,content
    int uid = root["uid"].asInt();
    int gid = root["gid"].asInt();
    string content = root["content"].asString();

    struct st_gNotice gnotice(uid, gid, content);
    // 持久化到群公告表
    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    // 更新用户数据
    string sql = util::Format("insert into group_notice(seq,uid,gid,content,sendtime) value(null,{0},{1},'{2}','{3}')", gnotice.uid, gnotice.gid, gnotice.content, gnotice.sendtime);
    printf("sql:%s\n", sql.data());
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }
    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);

    // 获取群的群成员
    vector<int> all_id = getGroupAllUserID(gnotice.gid);
    Json::Value m_root;
    m_root["cmd"] = Json::Value("new_groupnotice");
    m_root["uid"] = Json::Value(gnotice.uid);
    m_root["gid"] = Json::Value(gnotice.gid);
    m_root["content"] = Json::Value(gnotice.content);
    m_root["sendtime"] = Json::Value(gnotice.sendtime);
    string tmp = m_root.toStyledString();
    const char *new_group_notice = strdup(tmp.c_str());

    for (int i = 0; i < all_id.size(); i++)
    {
        struct bufferevent *fbev = judgeUserOnline(all_id[i]);
        if (fbev != nullptr)
        {
            bufferevent_write(fbev, new_group_notice, strlen(new_group_notice));
        }
    }
}

void Thread::dealGetFeed(Json::Value root, bufferevent *bev)
{
    // 解析 timeLineID
    int uid = root["timelineID"].asInt();

    MYSQL *conn = ConnectionPool::getInstance()->getConnObj();
    SqlQuery query(conn);
    // 查询用户及好友发送的动态
    string sql = util::Format("select announcer,t2.nick,pyqtype,content,sendtime,feedID from feed_storage t1 join `user` t2 on t1.announcer = t2.dd_num where announcer in (select dd_num from `user` where dd_num in (select fuid from friend_relation where uid = {0}) union all select dd_num from `user` where dd_num in(select uid from friend_relation where fuid = {0}) union all select {0}) order by `sendtime`", uid);
    if (query.exec(sql) == false)
    {
        printf("%s\n", query.getErrorText().data());
        ConnectionPool::getInstance()->recycleConnObj(conn);
        return;
    }
    // 获取结果集行数
    int rows = query.getRows();

    const char *ch = "$";

    // 有动态
    if (rows > 0)
    {
        printf("动态 rows:%d\n", rows);
        // 将动态添加到该用户的Feed同步TimeLine
        for (int i = 0; i < rows; i++)
        {
            struct st_feed feed;
            feed.announcer = atoi(query.getRes()[i][0].data());
            feed.nick = query.getRes()[i][1];
            feed.type = atoi(query.getRes()[i][2].data());
            feed.contect = query.getRes()[i][3];
            feed.sendtime = query.getRes()[i][4];
            feed.feedID = query.getRes()[i][5];
            toFeedSyncTimeLine(uid, feed);
        }
        // 给用户发送新动态通知
        Json::Value y_root;
        y_root["cmd"] = Json::Value("new_feed");
        string m_tmp = y_root.toStyledString();
        const char *new_feed = strdup(m_tmp.c_str()); // 新动态
        bufferevent_write(bev, new_feed, strlen(new_feed));
        bufferevent_write(bev, ch, strlen(ch));
    }

    // 回收数据库连接
    ConnectionPool::getInstance()->recycleConnObj(conn);
}

void *Thread::work(void *arg)
{
    Thread *t = (Thread *)arg;
    // printf("线程 : %ld 开始运行...\n",t->m_threadID);

    // 循环监听事件集合
    event_base_dispatch(t->m_base);

    // printf("线程 : %ld 退出...\n",t->m_threadID);

    return nullptr;
}

void Thread::read_cb(bufferevent *bev, void *arg)
{
    Thread *t = (Thread *)arg;

    char buf[4096] = {0};                               // bev的接收缓冲区默认大小是4096
    int size = bufferevent_read(bev, buf, sizeof(buf)); // 读数据,类似read()的作用
    if (size < 0)
    {
        printf("bufferevent_read error.\n");
        return;
    }

    vector<string> vec_cmd = t->split(buf, '$');
    for (int i = 0; i < vec_cmd.size(); i++)
    {
        Json::Reader reader;
        Json::Value root;
        if (reader.parse(vec_cmd[i], root))
        {                                       // true 验证通过,是json格式
            string tmp = root.toStyledString(); // 格式化json字符串
            cout << "recv:" << endl
                 << tmp;
            // 解析客户端发送的请求
            t->analysisRequest(vec_cmd[i], bev);
        }
    }
}

void Thread::write_cb(bufferevent *bev, void *arg)
{
}

void Thread::event_cb(bufferevent *bev, short events, void *arg)
{

    // events可用于判断当前发生了什么事件
    if (events & BEV_EVENT_EOF)
    { // 客户端断开连接
        printf("connection closed.\n");
    }
    else if (events & BEV_EVENT_ERROR)
    { // 其他错误
        printf("some other error.");
    }
}

void Thread::pipe_cb(bufferevent *bev, void *arg)
{
}
